package com.slz3.business.frame.sync;

import com.google.gson.Gson;
import com.slz3.business.frame.enums.ValidFlag;
import com.slz3.business.frame.module.DomainEntity;
import com.slz3.business.frame.redis.Jedis;
import com.slz3.business.frame.redis.RK;
import com.slz3.business.frame.util.VE;
import com.slz3.business.module.configManagement.conShareManage.domain.ConShareManage;
import com.slz3.business.module.configManagement.conShareManage.domain.ConShareManageCondition;
import com.slz3.business.module.configManagement.conShareManage.sync.ConShareManagePGToRedisSync;
import com.slz3.business.module.drawManagement.draFreeLottery.domain.DraFreeLottery;
import com.slz3.business.module.drawManagement.draFreeLottery.domain.DraFreeLotteryCondition;
import com.slz3.business.module.drawManagement.draFreeLottery.sync.DraFreeLotteryPGToRedisSync;
import com.slz3.business.module.drawManagement.draIntegralLottery.domain.DraIntegralLottery;
import com.slz3.business.module.drawManagement.draIntegralLottery.domain.DraIntegralLotteryCondition;
import com.slz3.business.module.drawManagement.draIntegralLottery.sync.DraIntegralLotteryPGToRedisSync;
import com.slz3.business.module.goodsManagement.baseGoods.domain.BaseGoods;
import com.slz3.business.module.goodsManagement.baseGoods.domain.BaseGoodsCondition;
import com.slz3.business.module.goodsManagement.baseGoods.sync.BaseGoodsPGToRedisSync;
import com.slz3.business.module.goodsManagement.gooGoods.domain.GooGoods;
import com.slz3.business.module.goodsManagement.gooGoods.domain.GooGoodsCondition;
import com.slz3.business.module.goodsManagement.gooGoods.sync.GooGoodsPGToRedisSync;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

@Slf4j
public class SyncPGToRedis {

    /**
     * 1 实体信息同步
     * 1.1 局部同步
     * 1.2 清数据全量同步
     * 2 valid uuid list
     * 3 id map uuid
     * 3.1 局部同步
     * 3.2 清数据全量同步
     * 4 custom uuid list
     */
    public static void sync(JpaRepository repository, DomainEntity domainEntity) throws Exception {
        /** base **/

        // base uuid list and entity list
        List<UUID> uuidList = SyncPGToRedisSteward.uuidList(domainEntity);
        List<DomainEntity> domainList = (List<DomainEntity>) repository.findAllById(uuidList).stream().filter(item -> item != null).collect(toList());
        List<DomainEntity> all = Optional.ofNullable(repository.findAll()).orElse(new ArrayList<>());
        List<DomainEntity> validAll = all.stream().filter(item -> ValidFlag.isValid(item.getValidFlag())).collect(toList());

        // check
        if (VE.isEmptyArr(uuidList, domainList, all, validAll))
            return;

        // base object
        RedisTemplate redisTemplate = Jedis.db0.redisTemplate;
        String domainClassName = domainEntity.getUuid() == null ?
                domainEntity.getClass().getSuperclass().getSimpleName() : domainEntity.getClass().getSimpleName();
        String domainClassTypeName = domainEntity.getUuid() == null ?
                domainEntity.getClass().getSuperclass().getTypeName() : domainEntity.getClass().getTypeName();

        //
        boolean clearDataFlag = Jedis.db0.getListLen(RK.CONFIG_DOMIN__$DOMAIN$__UUID_LIST.replace("${Domain}", domainClassName)) == 0;

        /** replace entity **/
        if (!clearDataFlag) {
            redisTemplate.opsForValue().multiSet(
                    domainList.stream().collect(toMap(
                            item -> String.format("%s:%s:%s:%s", RK.CONFIG_DOMIN, domainClassName, RK.DATA_JSON_STR, item.getUuid()),
                            item -> new Gson().toJson(item)
                    ))
            );
        } else {
            // 清数据 —— 全量更新
            redisTemplate.opsForValue().multiSet(
                    all.stream().collect(toMap(
                            item -> String.format("%s:%s:%s:%s", RK.CONFIG_DOMIN, domainClassName, RK.DATA_JSON_STR, item.getUuid()),
                            item -> new Gson().toJson(item)
                    ))
            );
        }

        /** valid status uuid list & set **/
        String validUuidSetKey = String.format("%s:%s", RK.UUID_SET, domainClassName); // TODO 废弃
        String validUuidListKey = RK.CONFIG_DOMIN__$DOMAIN$__UUID_LIST.replace("${Domain}", domainClassName);

        redisTemplate.delete(validUuidSetKey);
        redisTemplate.delete(validUuidListKey);

        redisTemplate.opsForSet().add(validUuidSetKey, validAll.stream().map(DomainEntity::getUuid).collect(toList()).toArray());
        redisTemplate.opsForList().rightPushAll(validUuidListKey, validAll.stream().map(DomainEntity::getUuid).collect(toList()));

        /** IdMapUuid - incrementId **/
        if (!clearDataFlag) {
            redisTemplate.opsForValue().multiSet(
                    domainList.stream().collect(toMap(
                            item -> SyncPGToRedisSteward.incrementIdMapUuidKey(item),
                            DomainEntity::getUuid
                    )).entrySet().stream().filter(item -> item.getKey() != null).collect(toMap(
                            item -> item.getKey(),
                            item -> item.getValue()
                    ))
            );
        } else {
            // 清数据 —— 全量更新
            redisTemplate.opsForValue().multiSet(
                    all.stream().collect(toMap(
                            item -> SyncPGToRedisSteward.incrementIdMapUuidKey(item),
                            DomainEntity::getUuid
                    )).entrySet().stream().filter(item -> item.getKey() != null).collect(toMap(
                            item -> item.getKey(),
                            item -> item.getValue()
                    ))
            );
        }

        /** custom **/
        if (domainClassTypeName.equals(GooGoods.class.getTypeName()) || domainClassTypeName.equals(GooGoodsCondition.class.getTypeName())) {
            GooGoodsPGToRedisSync.sync(redisTemplate, validAll);
        }
        if (domainClassTypeName.equals(DraFreeLottery.class.getTypeName()) || domainClassTypeName.equals(DraFreeLotteryCondition.class.getTypeName())) {
            DraFreeLotteryPGToRedisSync.sync(redisTemplate, validAll);
        }
        if (domainClassTypeName.equals(DraIntegralLottery.class.getTypeName()) || domainClassTypeName.equals(DraIntegralLotteryCondition.class.getTypeName())) {
            DraIntegralLotteryPGToRedisSync.sync(redisTemplate, validAll);
        }
        if (domainClassTypeName.equals(ConShareManage.class.getTypeName()) || domainClassTypeName.equals(ConShareManageCondition.class.getTypeName())) {
            ConShareManagePGToRedisSync.sync(redisTemplate, validAll);
        }
        if (domainClassTypeName.equals(BaseGoods.class.getTypeName()) || domainClassTypeName.equals(BaseGoodsCondition.class.getTypeName())) {
            BaseGoodsPGToRedisSync.sync(redisTemplate, validAll, uuidList);
        }

    }

}
